home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d16 / winvn060.arc / WVHEADER.C < prev    next >
Text File  |  1991-07-01  |  21KB  |  775 lines

  1. /* --- WVHEADER.C ---------------------------------------------
  2.  *
  3.  *  This file contains the code necessary to create the initial skeleton
  4.  *  version of an article, which will be edited by the user.
  5.  *
  6.  *  Mark Riordan   24-JAN-1990
  7.  */
  8.  
  9.  
  10. #include "windows.h"
  11. #include "wvglob.h"
  12. #include "winvn.h"
  13. #ifndef MAC
  14. #include "winundoc.h"
  15. #include <ctype.h>
  16. #include <time.h>
  17. #endif
  18.  
  19.  
  20. #define MAXHEADERLINE 256
  21.  
  22.  
  23. BOOL (*PostHeaderFuncs[])(TypDoc *Doc,char   *Buf,long int    BufLen) = {
  24.    MakeArtHeaderFrom,
  25.    MakeArtHeaderNewsgroups,
  26.    MakeArtHeaderSubject,
  27. /* MakeArtHeaderMessageID, */
  28. /* MakeArtHeaderDate,      */
  29.    MakeArtHeaderReferences,
  30.    MakeArtHeaderOrganization,
  31.    MakeArtHeaderNewsreader,
  32.    NULL
  33. };
  34.  
  35. BOOL (*MailHeaderFuncs[])(TypDoc *Doc,char   *Buf,long int    BufLen) = {
  36.    MakeArtHeaderTo,
  37.    MakeArtHeaderFrom,
  38.    MakeArtHeaderSubject,
  39.    MakeArtHeaderOrganization,
  40.    NULL
  41. };
  42.  
  43. /*--- function GetHeaderLine -------------------------------------------
  44.  *
  45.  *  Given a document, get a line from the header portion of that document
  46.  *  whose prefix matches a given prefix.  Prefix = first word in line.
  47.  *  For instance, you might call this routine to say "Get the 'Subject:'"
  48.  *  line from this document.
  49.  *
  50.  *    Entry    Doc      points to the document whose header we are scanning.
  51.  *                      The header is all the lines up to the first blank line.
  52.  *             Prefix   is the character string which will identify the
  53.  *                      line we are seeking.  It is the first word
  54.  *                      (blank-delimited) in a line in the header.
  55.  *             BufLen   is the number of bytes left in the buffer Buf.
  56.  *
  57.  *    Exit     Returns TRUE iff we returned a line.
  58.  *             Buf      if line was returned, contains that line, zero-
  59.  *                      terminated.
  60.  */
  61. BOOL
  62. GetHeaderLine(Doc,Prefix,Buf,BufLen)
  63. TypDoc *Doc;
  64. char *Prefix;
  65. char *Buf;
  66. int  BufLen;
  67. {
  68.    char *bufptr=Buf;
  69.    TypBlock far *BlockPtr;
  70.    TypLine far *LinePtr;
  71.    unsigned int Offset;
  72.    HANDLE hBlock;
  73.    TypLineID MyLineID;
  74.    int found = FALSE;
  75.  
  76.    TopOfDoc(Doc,&BlockPtr,&LinePtr);
  77.    while(ExtractTextLine(Doc,LinePtr,Buf,BufLen)) {
  78.  
  79.       /* Is this a blank line signifying the end of the header?      */
  80.  
  81.       if(IsLineBlank(Buf)) break;
  82.  
  83.       if(CompareStringNoCase(Buf,Prefix,strlen(Prefix)) == 0) {
  84.          found = TRUE;
  85.          break;
  86.       }
  87.       if(!NextLine(&BlockPtr,&LinePtr)) break;
  88.    }
  89.    UnlockLine(BlockPtr,LinePtr,&hBlock,&Offset,&MyLineID);
  90.    return (found);
  91. }
  92.  
  93. /*--- function CreatePostingWnd -----------------------------------------
  94.  *
  95.  *    Create the window for composing the text of a posting,
  96.  *    if it's OK to post.
  97.  *
  98.  *    Entry    Doc      points to the document to which we are posting
  99.  *                      a followup--NULL if it's a new posting.
  100.  *
  101.  *    Exit     Returns the handle of the newly-created window
  102.  *              (zero if failure).
  103.  */
  104.  
  105. HWND
  106. CreatePostingWnd(Doc,DocType)
  107. TypDoc *Doc;
  108. int DocType;
  109. {
  110.    int ih;
  111.    BOOL found = FALSE;
  112.    HWND hWnd = 0;
  113.    int width, AveCharWidth;
  114.    HDC hDC;
  115. #ifndef MAC
  116.    TEXTMETRIC  tmFontInfo;
  117. #endif
  118.    char *TitlePtr, *WndName;
  119.  
  120.    if(DocType == DOCTYPE_POSTING) {
  121.      WndName = "WinVnPost";
  122.      PostDoc = Doc;
  123.      if(Doc) {
  124.         TitlePtr = "Composing Followup Article";
  125.      } else {
  126.         TitlePtr = "Composing New Article";
  127.      }
  128.      for(ih=0; !found && ih<MAXPOSTWNDS; ih++) {
  129.         if(!hWndPosts[ih]) {
  130.            found = TRUE;
  131.            break;
  132.          }
  133.      }
  134.    } else {
  135.      WndName = "WinVnMail";
  136.      MailDoc = Doc;
  137.      if(Doc) {
  138.         TitlePtr = "Composing Reply Message";
  139.      } else {
  140.         TitlePtr = "Composing New Mail Message";
  141.      }
  142.      for(ih=0; !found && ih<MAXMAILWNDS; ih++) {
  143.         if(!hWndMails[ih]) {
  144.            found = TRUE;
  145.            break;
  146.          }
  147.      }
  148.    }
  149.    if(found && AuthenticatePosting()) {
  150. #ifndef MAC
  151.       hDC = GetDC(hWndConf);
  152.       GetTextMetrics(hDC,(LPTEXTMETRIC) &tmFontInfo);
  153.       AveCharWidth  = tmFontInfo.tmAveCharWidth;
  154.       ReleaseDC(hWndConf,hDC);
  155.  
  156.       if(xScreen > 78*AveCharWidth) {
  157.          width = 78*AveCharWidth;
  158.       } else {
  159.          width = xScreen - 2*AveCharWidth;
  160.       }
  161. #else
  162.       width = xScreen - 20;
  163. #endif
  164.  
  165.       hWnd = CreateWindow(WndName,
  166.       TitlePtr,
  167.       WS_OVERLAPPEDWINDOW /* | WS_VSCROLL */ ,
  168.       ih*CharWidth,     /* Initial X pos */
  169.       (int) (yScreen*3/8) + (1+ih)*LineHeight, /* Initial Y pos */
  170.       (int) width,                     /* Initial X Width */
  171.       (int) (yScreen*5/8) - (2*LineHeight),  /* Initial Y height */
  172.       NULL,
  173.       NULL,
  174.       hInst,
  175.       NULL);
  176.  
  177.       if (hWnd) {
  178. #ifndef MAC
  179.          ShowWindow(hWnd, SW_SHOWNORMAL);
  180. #else
  181.          MyShowWindow(hWnd, SW_SHOWNORMAL);
  182. #endif
  183.          UpdateWindow(hWnd);
  184.       }
  185.    }
  186.    return (hWnd);
  187. }
  188.  
  189.  
  190. /*--- function CreatePostingText ------------------------------------------
  191.  *
  192.  *    Create the text of the skeleton article to be edited by
  193.  *    the user before posting.   Display that text in an edit window.
  194.  */
  195. BOOL
  196. CreatePostingText(Doc,hWndPost,hWndEdit,DocType)
  197. TypDoc *Doc;
  198. HWND hWndPost;
  199. HWND hWndEdit;
  200. int DocType;
  201. {
  202.    long int BytesLeft;
  203.    char far *lpTextBuffer;
  204.    char far *lpCurPtr;
  205.    HANDLE hTextBuffer;
  206.    BOOL gotline;
  207.    char line[MAXHEADERLINE];
  208.    int ifunc;
  209.    int nLines;
  210.    long lParam;
  211.    int RefCount;
  212.    BOOL found;
  213.    BOOL (**HeaderFuncs)(TypDoc *Doc,char   *Buf,long int    BufLen);
  214. #ifdef MAC
  215.    long int textLength;
  216.    TEHandle TEH;
  217.    int ih;
  218.    Rect viewRect,destRect;
  219. #endif
  220.  
  221.    if(DocType == DOCTYPE_POSTING) {
  222.       HeaderFuncs = PostHeaderFuncs;
  223.    } else {
  224.       HeaderFuncs = MailHeaderFuncs;
  225.    }
  226.  
  227.    /* Compute the number of bytes we need to hold a straight ASCII representation
  228.     * of the initial text of the reply, and allocate a buffer of that size.
  229.     */
  230.    found = 0;
  231.    if(Doc) {
  232.       BytesLeft = (2 + NumBlocksInDoc(Doc)) * Doc->BlockSize;
  233.    } else {
  234.       BytesLeft = 3000;
  235.    }
  236.    if(NULL == (hTextBuffer = GlobalAlloc(GHND, (DWORD)BytesLeft))) {
  237.       MessageBox(hWndPost, "Cannot allocate memory for text","",MB_OK);
  238.       return FALSE;
  239.    }
  240.  
  241.    lpCurPtr = lpTextBuffer = GlobalLock(hTextBuffer);
  242.  
  243.    for(ifunc=0; HeaderFuncs[ifunc]; ifunc++) {
  244.       gotline = (HeaderFuncs[ifunc])(Doc,line,(long int)MAXHEADERLINE);
  245.       if(gotline) {
  246.          AppendTextToEditBuf(line,&lpCurPtr,&BytesLeft);
  247.       }
  248.    }
  249.    MakeArtBody(Doc,&lpCurPtr,&BytesLeft,DocType);
  250.  
  251.    /*  Set the edit window text to this skeleton article.            */
  252.  
  253. #ifndef MAC
  254.    SetWindowText(hWndEdit,lpTextBuffer);
  255. #else
  256.    viewRect = hWndPost->portRect;
  257.    viewRect.right -= SBarWidth;
  258.    viewRect.bottom -= SBarWidth;
  259.    destRect = viewRect;
  260.    destRect.left = 3;
  261.  
  262.    SetPort(hWndPost);
  263.    TEH = TENew(&destRect,&viewRect);
  264.    TEHCurrent = TEH;
  265.    (*TEH)->crOnly = -1;
  266.    textLength = lstrlen(lpTextBuffer);
  267.    TESetText(lpTextBuffer,textLength,TEH);
  268.    SetView(hWndPost);
  269.    ShowSelect(hWndPost);
  270.    TEUpdate(&destRect,TEH);
  271.  
  272.    for(ih=0,found=FALSE; !found && ih<MAXPOSTWNDS; ih++) {
  273.       if(hWndPosts[ih] == hWndPost) {
  274.          TEHPosts[ih] = TEH;
  275.          found = TRUE;
  276.          break;
  277.       }
  278.     }
  279.   /* mrr add here */
  280. #endif
  281.    GlobalUnlock(hTextBuffer);
  282.    GlobalFree(hTextBuffer);
  283. #if 0
  284.             strcpy(mesbuf,"Winc - Viewing ");
  285.             strncat(mesbuf,NewMemos[imemo],MAXMEMONAME);
  286.             SetWindowText(hWnd, mesbuf);
  287. #endif
  288. #ifndef MAC
  289.    nLines = (int) SendMessage(hWndEdit,EM_GETLINECOUNT,0,0L);
  290.    lParam = (long) ((long)nLines);
  291. /* while(nLines--) SendMessage(hWndEdit,WM_KEYDOWN,VK_DOWN,0L); */
  292. #endif
  293.    return TRUE;
  294. }
  295.  
  296. /*--- functions MakeArtHeaderXXXXX ---------------------------------------
  297.  *
  298.  *   Functions with names of the form MakeArtHeaderXxxxxx are all called
  299.  *   the same way and have similar purposes.  They are called to
  300.  *   create and return a line of text that will become a line in
  301.  *   the header of an article to be posted.  The source of
  302.  *   this information varies; it may be taken from an article
  303.  *   being replied to, it may be taken from a configuration file,
  304.  *   read from the system clock, etc.
  305.  *
  306.  *    Entry    Doc      points to a document containing an article
  307.  *                      being replied to; NULL if we're not replying
  308.  *                      to an article.
  309.  *             BufLen   is the length of the output buffer.
  310.  *
  311.  *    Exit     Returns TRUE iff we returned a line.
  312.  *             Buf      contains the line, if any, terminated by a
  313.  *                      zero byte.
  314.  */
  315.  
  316. /*--- function MakeArtHeaderSubject -------------------------------------
  317.  *
  318.  *    Returned "Subject:" line is blank if no previous Subject: line
  319.  *    could be found.  Otherwise, it is "Subject: Re: <previous subject>".
  320.  *    If the article being replied to had a subject already starting
  321.  *    with "Re:", the "Re:" is not repeated.
  322.  */
  323.  
  324. BOOL
  325. MakeArtHeaderSubject(Doc,Buf,BufLen)
  326. TypDoc *Doc;
  327. char   *Buf;
  328. long int    BufLen;
  329. {
  330.    char HeadLine[MAXHEADERLINE];
  331.    BOOL gotline;
  332.    char *outptr = Buf;
  333.    char *headptr = HeadLine;
  334.  
  335.    CopyBuf("Subject: ",&outptr,&BufLen);
  336.    if(Doc) {
  337.       gotline = GetHeaderLine(Doc,"Subject:",HeadLine,MAXHEADERLINE);
  338.       if(gotline) {
  339.          NextToken(&headptr);
  340.          if(CompareStringNoCase(headptr,"Re:",3) != 0) {
  341.             CopyBuf("Re: ",&outptr,&BufLen);
  342.          }
  343.          CopyBuf(headptr,&outptr,&BufLen);
  344.       }
  345.    }
  346.    return(TRUE);
  347. }
  348.  
  349. #if 0
  350. /*--- function MakeArtHeaderMessageID ----------------------------------
  351.  *
  352.  *    Returned "Message-ID:" line is computed from the time and
  353.  *    the ServerName (from Windows profile file).  This needs to
  354.  *    be improved.
  355.  */
  356. BOOL
  357. MakeArtHeaderMessageID(Doc,Buf,BufLen)
  358. TypDoc *Doc;
  359. char   *Buf;
  360. long int    BufLen;
  361. {
  362. #define MAXSERVERNAME 32
  363.    char ServerName[MAXSERVERNAME];
  364.  
  365.    GetProfileString(szAppName,"ServerName","msuinfo.cl.msu.edu",
  366.       ServerName,MAXSERVERNAME);
  367.  
  368.    sprintf(Buf,"Message-ID: <%ld@%s>",time((time_t *)NULL),ServerName);
  369.    return TRUE;
  370. }
  371. #endif
  372.  
  373. /*--- function MakeArtHeaderFrom ----------------------------------
  374.  *
  375.  *  Returned "From:" is taken from Windows profile entries.
  376.  */
  377. BOOL
  378. MakeArtHeaderFrom(Doc,Buf,BufLen)
  379. TypDoc *Doc;
  380. char   *Buf;
  381. long int    BufLen;
  382. {
  383.    char *outptr = Buf;
  384.  
  385.    CopyBuf("From: ",&outptr,&BufLen);
  386.    if(MailAddress[0]) {
  387.       CopyBuf(MailAddress,&outptr,&BufLen);
  388.    } else {
  389.       CopyBuf("<Unknown>",&outptr,&BufLen);
  390.    }
  391.    if(UserName[0]) {
  392.       CopyBuf(" (",&outptr,&BufLen);
  393.       CopyBuf(UserName,&outptr,&BufLen);
  394.       CopyBuf(")",&outptr,&BufLen);
  395.    }
  396.  
  397.    return TRUE;
  398. }
  399.  
  400. /*--- function MakeArtHeaderTo ----------------------------------
  401.  *
  402.  *  Simply returns a blank "To:" line.
  403.  */
  404. BOOL
  405. MakeArtHeaderTo(Doc,Buf,BufLen)
  406. TypDoc *Doc;
  407. char   *Buf;
  408. long int    BufLen;
  409. {
  410.    char HeadLine[MAXHEADERLINE];
  411.    char *outptr = Buf, *cptr=HeadLine;
  412.    BOOL gotwho;
  413.  
  414.    CopyBuf("To: ",&outptr,&BufLen);
  415.    if(Doc) {
  416.       gotwho = GetHeaderLine(Doc,"Reply-To:",HeadLine,MAXHEADERLINE);
  417.       if(!gotwho) {
  418.          gotwho = GetHeaderLine(Doc,"From:",HeadLine,MAXHEADERLINE);
  419.       }
  420.       if(gotwho) {
  421.          NextToken(&cptr);
  422.          while(*cptr && *cptr!=' ') {
  423.             *(outptr++) = *(cptr++);
  424.          }
  425.          *outptr = '\0';
  426.       }
  427.    }
  428.  
  429.    return TRUE;
  430. }
  431.  
  432. /*--- function MakeArtHeaderOrganization ----------------------------------
  433.  *
  434.  *    Returned "Organization:" line is gotten from the Windows
  435.  *    profile file.
  436.  */
  437. BOOL
  438. MakeArtHeaderOrganization(Doc,Buf,BufLen)
  439. TypDoc *Doc;
  440. char   *Buf;
  441. long int    BufLen;
  442. {
  443.    char *outptr = Buf;
  444.  
  445.    if(Organization[0]) {
  446.       CopyBuf("Organization: ",&outptr,&BufLen);
  447.       CopyBuf(Organization,&outptr,&BufLen);
  448.       return (TRUE);
  449.    }
  450.  
  451.    return FALSE;
  452. }
  453.  
  454. /*--- function MakeArtHeaderNewsreader ----------------------------------
  455.  *
  456.  *    Returned "Newsreader: " line is simply a constant.
  457.  */
  458. BOOL
  459. MakeArtHeaderNewsreader(Doc,Buf,BufLen)
  460. TypDoc *Doc;
  461. char   *Buf;
  462. long int    BufLen;
  463. {
  464.    char *outptr = Buf;
  465.  
  466.    CopyBuf("Newsreader: ",&outptr,&BufLen);
  467.    CopyBuf("MS Windows ",&outptr,&BufLen);
  468.    CopyBuf(szAppName,&outptr,&BufLen);
  469.    return (TRUE);
  470.  
  471. }
  472.  
  473. #if 0
  474. /*--- function MakeArtHeaderDate ----------------------------------
  475.  *
  476.  *    Returned "Date:" line is computed from operating system time.
  477.  *    Be sure to set the TZ environment variable correctly for
  478.  *    "grtime" to work properly.  Typical setting:  SET TZ=EST5
  479.  */
  480. BOOL
  481. MakeArtHeaderDate(Doc,Buf,BufLen)
  482. TypDoc *Doc;
  483. char   *Buf;
  484. long int    BufLen;
  485. {
  486.    struct tm *timeptr;
  487.    time_t curtime;
  488.  
  489.    curtime = time((time_t *) NULL);
  490.    timeptr = gmtime(&curtime);
  491.    sprintf(Buf,"Date: %.4d-%.2d-%.2d %.2d:%.2d GMT",timeptr->tm_year+1900,
  492.      timeptr->tm_mon+1,timeptr->tm_mday,timeptr->tm_hour,timeptr->tm_min);
  493.    return TRUE;
  494. }
  495. #endif
  496.  
  497. /*--- function MakeArtHeaderReferences -----------------------------------
  498.  *
  499.  *  Returned "References:" line contains all the previous article's
  500.  *  References (if any), plus its Message-ID (if any).
  501.  */
  502. BOOL
  503. MakeArtHeaderReferences(Doc,Buf,BufLen)
  504. TypDoc *Doc;
  505. char   *Buf;
  506. long int    BufLen;
  507. {
  508.    char HeadLine[MAXHEADERLINE];
  509.    BOOL gotrefs;
  510.    BOOL gotmesID;
  511.    char *outptr = Buf;
  512.    char *headptr = HeadLine;
  513.  
  514.  
  515.    if(Doc) {
  516.       gotrefs = GetHeaderLine(Doc,"References:",HeadLine,MAXHEADERLINE);
  517.       if(gotrefs) {
  518.          CopyBuf(HeadLine,&outptr,&BufLen);
  519.          CopyBuf(" ",&outptr,&BufLen);
  520.       }
  521.       gotmesID = GetHeaderLine(Doc,"Message-ID:",HeadLine,MAXHEADERLINE);
  522.       if(gotmesID) {
  523.          if(!gotrefs) {
  524.             CopyBuf("References: ",&outptr,&BufLen);
  525.          }
  526.          NextToken(&headptr);
  527.          CopyBuf(headptr,&outptr,&BufLen);
  528.       }
  529.       if(gotrefs || gotmesID) return(TRUE);
  530.    }
  531.    return FALSE;
  532. }
  533.  
  534. /*--- function MakeArtHeaderNewsgroups -----------------------------------
  535.  *
  536.  *  Returned "Newsgroups:" line is simply a copy of previous article's.
  537.  */
  538. BOOL
  539. MakeArtHeaderNewsgroups(Doc,Buf,BufLen)
  540. TypDoc *Doc;
  541. char   *Buf;
  542. long int    BufLen;
  543. {
  544.    char HeadLine[MAXHEADERLINE];
  545.    BOOL gotnews = FALSE;
  546.    char *outptr = Buf;
  547.  
  548.    if(Doc) {
  549.       gotnews = GetHeaderLine(Doc,"Newsgroups:",HeadLine,MAXHEADERLINE);
  550.       if(gotnews) {
  551.          CopyBuf(HeadLine,&outptr,&BufLen);
  552.       }
  553.    }
  554.    if(!gotnews) {
  555.       CopyBuf("Newsgroups: ",&outptr,&BufLen);
  556.       CopyBuf(NewsgroupsPtr,&outptr,&BufLen);
  557.    }
  558.    return TRUE;
  559. }
  560.  
  561. /*--- function MakeArtBody ----------------------------------------------
  562.  *
  563.  *    Make the body of the article.  This is null if there's no article
  564.  *    to reply to, else it's text of the form:
  565.  *    In article <Message-ID>, <user> says:
  566.  *    >line 1
  567.  *    >line 2
  568.  *    > .....
  569.  *
  570.  *    Entry    Doc      points to the article being replied to, else
  571.  *                      NULL if none.
  572.  *             left     is the number of bytes left in MesBuf.
  573.  *
  574.  *    Exit     MesBuf   contains the added lines, and has been updated
  575.  *                      to point to just after the last added byte.
  576.  *             left     has been decremented appropriately.
  577.  *             Return value is not used, for now.
  578.  */
  579. BOOL MakeArtBody(Doc,MesBuf,left,DocType)
  580. TypDoc *Doc;
  581. char far **MesBuf;
  582. long int  *left;
  583. int DocType;
  584. {
  585.    HANDLE hBlock;
  586.    unsigned int Offset;
  587.    TypLineID MyLineID;
  588.    TypBlock far *BlockPtr;
  589.    TypLine far *LinePtr;
  590.    char mesID[MAXHEADERLINE];
  591.    char from[MAXHEADERLINE];
  592.    char line[MAXHEADERLINE];
  593.    BOOL gotmesID,gotfrom;
  594.    char *outptr = line;
  595.    char *fromptr=from;
  596.    char *mesptr=mesID;
  597.  
  598.    AppendTextToEditBuf("",MesBuf,left);  /* blank line after header */
  599.  
  600.    /* Create the "In message xxx, yyy says:" line.                   */
  601.  
  602.    if(Doc) {
  603.       gotmesID = GetHeaderLine(Doc,"Message-ID:",mesID,MAXHEADERLINE);
  604.       if(gotmesID) {
  605.          NextToken(&mesptr);
  606.       } else {
  607.          mesptr = "<Unknown>";
  608.       }
  609.       if(DocType == DOCTYPE_POSTING) {
  610.          gotfrom = GetHeaderLine(Doc,"From:",from,MAXHEADERLINE);
  611.          if(gotfrom) {
  612.             NextToken(&fromptr);
  613.          } else {
  614.             fromptr = "<Unknown>";
  615.          }
  616.          sprintf(line,"In article %s, %s says:",mesptr,fromptr);
  617.       } else {
  618.          sprintf(line,"In article %s, you say:",mesptr);
  619.       }
  620.       AppendTextToEditBuf(line,MesBuf,left);
  621.  
  622.       /* Skip past header of reply document.                            */
  623.  
  624.       TopOfDoc(Doc,&BlockPtr,&LinePtr);
  625.       while(ExtractTextLine(Doc,LinePtr,line,MAXHEADERLINE) &&
  626.         !IsLineBlank(line) ) {
  627.          if(!NextLine(&BlockPtr,&LinePtr)) break;
  628.       }
  629.  
  630.       /* Copy body of reply document into the body of this article,  */
  631.       /* prepending a ">" to each line.                              */
  632.  
  633.       line[0] = '>';
  634.       while(ExtractTextLine(Doc,LinePtr,line+1,MAXHEADERLINE-1)) {
  635.          AppendTextToEditBuf(line,MesBuf,left);
  636.          if(!NextLine(&BlockPtr,&LinePtr)) break;
  637.       }
  638.       UnlockLine(BlockPtr,LinePtr,&hBlock,&Offset,&MyLineID);
  639.    }
  640.    return TRUE;
  641. }
  642.  
  643.  
  644. /*--- function CompareStringNoCase -------------------------------------
  645.  *
  646.  *   Compare two strings, case insensitive.
  647.  *
  648.  *    Entry    str1, str2  are two strings to compare.
  649.  *             slen        is the number of characters to compare
  650.  *                         (but stop at a zero byte).
  651.  *
  652.  *    Exit     returns -1 if str1 is earlier in collating sequence,
  653.  *              0 if strings are equal, 1 otherwise
  654.  */
  655. int
  656. CompareStringNoCase(str1,str2,slen)
  657. char *str1;
  658. char *str2;
  659. int slen;
  660. {
  661.    while (slen-- && *str1 && *str2) {
  662.       if(_tolower(*str1) < _tolower(*str2)) {
  663.          return(-1);
  664.       } else if(_tolower(*str1) > _tolower(*str2)) {
  665.          return(1);
  666.       }
  667.       str1++;  str2++;
  668.    }
  669.    return(0);
  670. }
  671.  
  672. /*--- function CopyBuf -----------------------------------------------
  673.  *
  674.  *    Copy a string into a buffer, being sure not to overrun the
  675.  *    buffer.
  676.  *
  677.  *    Entry    instr    points to the string to copy into the buffer,
  678.  *                      zero-terminated.
  679.  *             buf      is the buffer
  680.  *             left     is the number of bytes left in the buffer
  681.  *    Exit     buf      contains the LWA+1 of the bytes copied into
  682.  *                      the output buffer.  A Zero byte is stored
  683.  *                      into this location.
  684.  *             left     is the number of bytes left in the buffer.
  685.  */
  686.  
  687. void
  688. CopyBuf(instr,buf,left)
  689. char *instr;
  690. char **buf;
  691. long int      *left;
  692. {
  693.    while (--(*left) > 1 && *instr) {
  694.       *((*buf)++) = *(instr++);
  695.    }
  696.    if(*left > 0) **buf = '\0';
  697. }
  698.  
  699. /*--- function NextToken -----------------------------------------------
  700.  *
  701.  *  Position a pointer to the next token in a string.
  702.  *  Delimiters are space and tab.
  703.  *
  704.  *    Entry    cptr     points to a position in a zero-terminated string.
  705.  *
  706.  *    Exit     Returns TRUE iff a next token was found.
  707.  *             cptr     points to the next token, if found--else
  708.  *                      it is unchanged.
  709.  */
  710. BOOL
  711. NextToken(cptr)
  712. char **cptr;
  713. {
  714.    /* Skip to end of current token, if any.              */
  715.  
  716.    while(**cptr!=' ' && **cptr!='\t' && **cptr) (*cptr)++;
  717.  
  718.    /* Skip past white space.                             */
  719.  
  720.    while(**cptr && (**cptr==' ' || **cptr=='\t')) (*cptr)++;
  721.    if(**cptr) {
  722.       return(TRUE);
  723.    } else {
  724.       return(FALSE);
  725.    }
  726. }
  727.  
  728. /*--- function AppendTextToEditBuf ----------------------------------------
  729.  *
  730.  *    Appends a zero-terminated text line to a buffer to be given
  731.  *    to an Edit window.  Used in building messages to be displayed
  732.  *    and edited by an Edit window.
  733.  *
  734.  *    Entry    instr    points to a text line to add.  It is terminated
  735.  *                      by a zero byte and does not end in CR or LF.
  736.  *             left     is the number of characters left in buf.
  737.  *
  738.  *    Exit     buf      contains the line, terminated by CR and LF.
  739.  *                      buf now points to the next available byte.
  740.  *             left     has been decremented as appropriate.
  741.  */
  742. void
  743. AppendTextToEditBuf(instr,buf,left)
  744. char *instr;
  745. char far **buf;
  746. long int      *left;
  747. {
  748.    while (--(*left) > 0 && *instr) {
  749.       *((*buf)++) = *(instr++);
  750.    }
  751.    if(--(*left) > 0) *((*buf)++) = '\r';
  752. #ifndef MAC
  753.    if(--(*left) > 0) *((*buf)++) = '\n';
  754. #endif
  755.    if((*left) > 0)   **buf = '\0';
  756. }
  757.  
  758. /*--- function IsLineBlank ------------------------------------------------
  759.  *
  760.  *    Determine whether a zero-terminated line is blank.
  761.  *    "Blank" means it contains nothing but spaces and tabs.
  762.  *
  763.  *    Entry    line     points to the line.
  764.  *
  765.  *    Exit     returns TRUE iff the line is blank.
  766.  */
  767. BOOL
  768. IsLineBlank(line)
  769. char far *line;
  770. {
  771.    while(*line==' ' || *line=='\t' || *line=='\n') line++;
  772.    return (!(*line));
  773. }
  774. 
  775.